/* SchedulerC.java
 * 
 * Alex Schwartz
 * Derek Dupuis
 * Greg Warner
 * Mike Dixey
 * 
 * Second level of scheduling, tries to split group in
 * events that dont work
 * 
 */

import java.util.*;
import java.text.*;

public class SchedulerC implements ScheduleIF
{
   public boolean schedule( TourApp tA, TourOff tO )
   {
      EventColl events = tO.tour().events();
      
      Event e;
      GregorianCalendar start, end;
      
      //must check all events for conflict
      for( int i = 0; i < events.size(); i++ )
      {
         e = events.get( i );
         
         //calculate start and end time of event
         start = (GregorianCalendar)tO.startDate().clone();
         end = (GregorianCalendar)tO.startDate().clone();
         start.add( Calendar.DAY_OF_MONTH, 
                   e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 );
         start.add( Calendar.HOUR_OF_DAY,
                   e.startTime().get( Calendar.HOUR_OF_DAY ) );
         start.add( Calendar.MINUTE,
                   e.startTime().get( Calendar.MINUTE ) );
         
         end.add( Calendar.DAY_OF_MONTH, 
                 e.endTime().get( Calendar.DAY_OF_MONTH ) - 1 );
         end.add( Calendar.HOUR_OF_DAY,
                 e.endTime().get( Calendar.HOUR_OF_DAY ) );
         end.add( Calendar.MINUTE,
                 e.endTime().get( Calendar.MINUTE ) );
         //check if event works with provider
         Provider p = e.provider();
         
         //if cant fit normally, check if splitting works
         if( p.service().type().compareTo( "lodging" ) == 0 )
         {
            
            if( p.conflict( tO.roomsNeeded(), start, end ) )
            {
               //if group cannot be split, return, then try method B
               if( !trySplit( tA, e, start, end, tO.roomsNeeded() ) )
                  return false;
            }
         }
         else if( p.conflict( tO.size(), start, end ) )
         {
            //if group cannot be split, return, then try method B
            if( !trySplit( tA, e, start, end, tO.size() ) )
               return false;
         }
      }
      
      //if it gets here, no conflict detected schedule all events
      for( int i = 0; i < events.size(); i++ )
      {
         e = events.get( i );
         
         //calculate start and end time of event
         start = (GregorianCalendar)tO.startDate().clone();
         end = (GregorianCalendar)tO.startDate().clone();
         start.add( Calendar.DAY_OF_MONTH, 
                   e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 );
         start.add( Calendar.HOUR_OF_DAY,
                   e.startTime().get( Calendar.HOUR_OF_DAY ) );
         start.add( Calendar.MINUTE,
                   e.startTime().get( Calendar.MINUTE ) );
         
         end.add( Calendar.DAY_OF_MONTH, 
                 e.endTime().get( Calendar.DAY_OF_MONTH ) - 1 );
         end.add( Calendar.HOUR_OF_DAY,
                 e.endTime().get( Calendar.HOUR_OF_DAY ) );
         end.add( Calendar.MINUTE,
                 e.endTime().get( Calendar.MINUTE ) );
         //schedule event
         Provider p = e.provider();
         if( p.service().type().compareTo( "lodging" ) == 0 )
         {
            if( p.conflict( tO.roomsNeeded(), start, end ) )
            {
               scheduleSplit( tO, tA, e, start, end, tO.roomsNeeded() );
            }
            else
               p.addBooking( new Booking( tO.roomsNeeded(), start, end ) );
         }
         else 
         {
            if( p.conflict( tO.size(), start, end ) )
            {
               scheduleSplit( tO, tA, e, start, end, tO.size() );
            }
            else
               p.addBooking( new Booking( tO.size(), start, end ) );
         }
         
      }
      
      return true;
   }
   
   boolean trySplit( TourApp tA, Event e, GregorianCalendar start, GregorianCalendar end,
                    int cap )
   {
      int halfCap = ( cap + 1 ) / 2;
      Set    p = tA.providers().keySet( );
      Provider prov = e.provider();
      Provider newProv;
      
      Iterator iter = p.iterator();
      if( prov.conflict( halfCap, start, end ) )
         return false;
      
      while( iter.hasNext() )
      {
         newProv = tA.providers().get( iter.next() );
         
         int iStart = start.get( Calendar.HOUR_OF_DAY ) * 100 + start.get( Calendar.MINUTE );
         int iEnd = end.get( Calendar.HOUR_OF_DAY ) * 100 + end.get( Calendar.MINUTE );
         int iOpen = newProv.openTime().get( Calendar.HOUR_OF_DAY ) * 100 + 
            newProv.openTime().get( Calendar.MINUTE );
         int iClose = newProv.closeTime().get( Calendar.HOUR_OF_DAY ) * 100 + 
            newProv.closeTime().get( Calendar.MINUTE );
         
         if( iOpen > iStart || iEnd > iClose )
            continue;
         
         if( newProv != prov && 
            newProv.service().type().compareTo( prov.service().type() ) == 0 )
         {
            if( !newProv.conflict( halfCap, start, end ) )
            {
               return true;
            }
         }
      }
      
      return false;
      
      
   }
   
   void scheduleSplit( TourOff tO, TourApp tA, Event e, GregorianCalendar start, GregorianCalendar end,
                      int cap )
   {
      int halfCap = ( cap + 1 ) / 2;
      Set    p = tA.providers().keySet( );
      Provider prov = e.provider();
      Provider newProv;
      
      Iterator iter = p.iterator();
      
      prov.addBooking( new Booking( halfCap, start, end ) );
      System.out.printf( "Offering: %s, half the people went to %s and ",
                        tO.offeringName(), prov.name() );
      while( iter.hasNext() )
      {
         newProv = tA.providers().get( iter.next() );
         if( newProv != prov && 
            newProv.service().type().compareTo( prov.service().type() ) == 0 )
         {
            if( !newProv.conflict( halfCap, start, end ) )
            {
               newProv.addBooking( new Booking( halfCap, start, end ) );
               System.out.printf( "half went to %s.", newProv.name() );
               break;
            }
         }
      }
      
      
      
   }
}